package com.zxj.common.core.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.zxj.common.core.contains.Constants;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 线程存储副本工具类
 * TTL：能够在线程池中执行任务时，将 ThreadLocal 的值透传给后续线程，确保数据的正确性。
 * 这是 TTL 与原生 ThreadLocal 最显著的区别。
 * 原生 ThreadLocal 在线程池中的线程复用时会导致数据共享问题，因为线程池中的线程可能会被多个任务共享。
 *
 * @author zxj2022
 * @date 2025/01/08
 */
public class ThreadLocalUtil {
    /** 线程本地 */
    private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>();

    /**
     * 设置kv数据
     *
     * @param key 钥匙
     * @param value 价值
     */
    public static void set(String key, Object value) {
        Map<String, Object> map = getLocalMap();
        map.put(key, value == null ? StrUtil.EMPTY : value);
    }

    /**
     * 依据key获取value
     *
     * @param key 钥匙
     * @param clazz value的类型
     * @return {@link T }
     */
    public static <T> T get(String key, Class<T> clazz) {
        Map<String, Object> map = getLocalMap();
        return (T) map.getOrDefault(key, null);
    }

    /**
     * 获取线程本地数据
     *
     * @return {@link Map }<{@link String }, {@link Object }>
     */
    public static Map<String, Object> getLocalMap() {
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            map = new ConcurrentHashMap<String, Object>();
            THREAD_LOCAL.set(map);
        }
        return map;
    }

    /**
     * 删除
     *
     */
    public static void remove() {
        THREAD_LOCAL.remove();
    }


    /**
     * 设置用户id
     * @param userId 用户id
     */
    public static void setUserId(Long userId) {
        set(Constants.USER_ID, userId);
    }

    /**
     * 获取用户id
     * @return 用户id
     */
    public static Long getUserId() {
        return get(Constants.USER_ID, Long.class);
    }


    /**
     * 设置用户key
     * @param userKey 用户key
     */
    public static void setUserKey(String userKey) {
        set(Constants.USER_KEY, userKey);
    }

    /**
     * 获取用户key
     * @return 用户key
     */
    public static String getUserKey() {
        return get(Constants.USER_KEY, String.class);
    }


}